// #include <iostream>
// #include <unistd.h>
// #include <pthread.h>
// #include <cerrno>
// #include <string.h>

// using namespace std;

// void* thread1(void* args)
// {
//     cout<<"thread 1 returning"<<endl;
//     int* p=(int*)malloc(sizeof(int));
//     *p=1;
//     return (void*)p;
// }

// void* thread2(void* args)
// {
//     cout<<"thread 2 exiting"<<endl;
//     int* p=(int*)malloc(sizeof(int));
//     *p=2;
//     pthread_exit((void*)p);
// }
// //这里的线程无法自动退出需要手动退出
// void* thread3(void* args)
// {
//     while(true)
//     {
//         cout<<"thread 3 running"<<endl;
//         sleep(1);
//     }
//     return nullptr;
// }
// int main()
// {
//     pthread_t tid;
//     void* ret
//     pthread_create(&tid,nullptr,thread1,nullptr);
//     pthread_join(tid,&ret);
//     printf("thread return:thread id:%X,thread code:%d",\
//     tid,*(int*)ret);
//     cout<<endl;
//     free(ret);

//     pthread_create(&tid,nullptr,thread2,nullptr);
//     pthread_join(tid,&ret);
//      printf("thread return:thread id:%X,thread code:%d",\
//     tid,*(int*)ret);
//     cout<<endl;
//     free(ret);

//     pthread_create(&tid,nullptr,thread3,nullptr);
//     sleep(3);
//     pthread_cancel(tid);
//     pthread_join(tid,&ret);
//     if(ret == PTHREAD_CANCELED)
//     {
//         printf("thread return : thread id:%X,thread code:PTHREAD_CANCELED");
//     }
//     else
//     {
//         printf("thread return : thread id:%X,thread code:NULL",tid);
//     }
//     return 0;
// }
// // void *thread1(void *args)
// // {
// //     cout << "thread 1 returning..." << endl;
// //     int *p = (int *)malloc(sizeof(int));
// //     *p = 1;
// //     return (void *)p;
// // }

// // void *thread2(void *args)
// // {
// //     cout << "thread 2 exiting..." << endl;
// //     int *p = (int *)malloc(sizeof(int));
// //     *p = 2;
// //     pthread_exit((void *)p);
// // }

// // void *thread3(void *args)
// // {
// //     while (true)
// //     {
// //         cout << "thread 3 is runing..." << endl;
// //         sleep(1);
// //     }
// //     return nullptr;
// // }
// /*
// void pthread_join(pthread_t tid,void** ret)
// void pthread_self(pthread_t tid)
// void pthread_exit(void* value_ptr)
// //这里的value_ptr会指向一个传入的参数作为线程的退出码，这个指针可以将内容传递给其他线程，也可以在线程
// 等待的时候作为参数传递过去
// pthread_self()用于获得自身的ID
// //最后的结果取决于线程的两个状态，如果线程存在的话，那么retval存放的就是线程的返回状态，如果线程已经不存在
// 了的话，那么这个指针就放置着PTHREAD_CANCELED
// pthread_join(pthread_t,void** value_ptr)
// 这是一个指针，后者指向线程的返回值
// /如果retval不是NULL则pthread_join()复制目标线程的退出状态（即目标线程提供给pthread_exit（3））的值）
// 到retval指针。 如果目标线程已取消(pthread_cancel(pthread_t tid))，则放置PTHREAD_CANCELED在retval指出的位置。

// pthread_exit(void* value_ptr)
// 这个函数可以终止调用线程，并且通过value_ptr返回一个值，如果线程之间可以连接的话，这个值也可以分享给
// 另外一个线程使用，也就是说这里是不需要有返回值的，只要value_ptr指针就可以指出
// /pthread_exit（） 函数终止调用线程，并通过 retval 返回一个值（如果线程可连接）可供另一个线程使用
//        线程在调用 pthread_join（3） 的同一进程中。
// */
// // int main()
// // {
// //     pthread_t tid;
// //     void *ret;
// //     pthread_create(&tid, nullptr, thread1, nullptr);
// //     // 调用结束以后成功返回0，否则返回他的错误码保存在ret当中
// //     //这里在等待线程结束的时候，线程的结束状态会保存在这个二级指针当中
// //     pthread_join(tid, &ret);
// //     printf("thread return,thread id:%X,thread code:%d\n", tid, *(int *)ret);
// //     free(ret);

// //     pthread_create(&tid, nullptr, thread2, nullptr);
// //     pthread_join(tid, &ret);
// //     printf("thread return,thread id:%X,thread code:%d\n", tid, *(int *)ret);
// //     free(ret);

// //     pthread_create(&tid, nullptr, thread3, nullptr);
// //     sleep(3);
// //     // 直接输入线程的id就可以直接将线程取消掉
// //     pthread_cancel(tid);
// //     pthread_join(tid, &ret);
// //     if (ret == PTHREAD_CANCELED)
// //     {
// //         printf("thread return,thread id:%X,thread code:PTHREAD_CENCELED");
// //     }
// //     else
// //     {
// //         // 这里的%X以十六进制数形式表示
// //         printf("thread return,thread id:%X,thread code:NULL", tid);
// //     }
// //     return 0;
// // }
// /*
// 关于进程和线程的问题：
//     与线程相关的函数是一个完整的序列大多数以pthread开头
// pthread_create()是一个线程的创建函数，函数本身会返回线程的
// ID，第二个参数是设置线程的属性，如果指控就设置为默认属性，
// 第三个参数是线程要参与回调的函数，线程启动以后要执行的动作
// 最后一个参数就是线程回调函数的参数；
//     如果这个接口调用成功的话，那么就返回0，如果失败就返回错误码

// 传统的一些函数是成功返回0，失败的话返回-1，并且对全局变量
// errno赋值并且通过调用strerrno接口来指示错误
// pthread不会设置errno全局变量，而是错误代码通过返回值返回

// 线程终止：
//     如果只是想要终止线程而不是终止整个进程可以有三种方法
// 从线程函数中return，这种方法对主线程不适用，如果主线程
// return相当于终止整个进程
// 2.线程可以调用pthread_exit()来终止自己
// 3.也可以通过pthread_cancel()来终止同一进程当中的另一个线程

// void pthread_exit(void* value_ptr)只能指向一个malloc分配的地址和一个全局变量
// 不能指向一个局部变量，因为当其他线程得到这个指针的时候，线程
// 函数已经结束了

// //线程的取消是需要一个结果的
// int pthread_cancel(pthread_t )
// 取消一个执行中的线程
// 如果成功的话则返回0，失败的话返回错误码
// 这里要问一下，为什么需要线程等待
// 已经退出的线程，他的空间没有被释放，仍然在进程的地址空间内，而创建
// 出新的线程不会重复使用刚才退出的线程地址空间

// int pthread_join(pthread_t thread,void** value_ptr)
// 作用是等待线程的结束，这个函数没有返回值后者指向线程的返回值，如果成功的话
// 就返回0，失败的话就返回错误码

// void pthread_exit(void* value_ptr)

// int pthread_cancel(pthread_t thread)

// int pthread_join(ptherad_t ,void** value_ptr)


// 如果线程是通过return返回的话，指针所指向的单元中存放的内容
// 是线程函数的返回值

// 如果thread线程被别的线程调用pthread_cancel异常终止掉，ptr所指向
// 的单元里面是常数PTHREAD_CANCELED
// 如果对于线程的终止状态不感兴趣的话可以传递nullptr给value_ptr参数


// */
// // void* threadRoutine(void* args)
// // {
// //     int i=0;
// //     int* data =new int[10];
// //     while(true)
// //     {
// //         cout<<"new thread"<<(char*)args<<"running..."
// //         <<pthread_self()<<endl;
// //         sleep(1);
// //         // data[i]=i;
// //         // if(i++==3)
// //         //     break;
// //         // int a=10;
// //         // a/=0;
// //     }
// //     pthread_exit((void*)11);
// //     cout<<"new thread quit"<<endl;
// //     return (void*)10;
// // }

// // void *thread1(void *args)
// // {
// //     cout << "thread 1 returning..." << endl;
// //     int *p = (int *)malloc(sizeof(int));
// //     *p = 1;
// //     return (void *)p;
// // }
// // void *thread2(void *args)
// // {
// //     cout << "thread 2 exiting" << endl;
// //     int *p = (int *)malloc(sizeof(int));
// //     *p = 2;
// //     pthread_exit((void *)p);
// // }
// // void *thread3(void *args)
// // {
// //     while (1)
// //     {
// //         cout << "thread 3 is running" << endl;
// //         sleep(1);
// //     }
// //     return nullptr;
// // }

// // int main(void)
// // {
// //     pthread_t tid;
// //     void *ret;
// //     // thread 1 return
// //     pthread_create(&tid, NULL, thread1, NULL);
// //     pthread_join(tid, &ret);
// //     printf("thread return, thread id %X, return code:%d\n", tid, *(int *)ret);
// //     //这里的free这只是释放了对象的内存但是并不会调用析构函数，所以ret只是数据被清空但是这个指针还在
// //     //下次可以继续使用
// //     free(ret);
// //     // thread 2 exit
// //     pthread_create(&tid, NULL, thread2, NULL);
// //     pthread_join(tid, &ret);
// //     printf("thread return, thread id %X, return code:%d\n", tid, *(int *)ret);
// //     free(ret);
// //     // thread 3 cancel by other
// //     pthread_create(&tid, NULL, thread3, NULL);
// //     sleep(3);
// //     pthread_cancel(tid);
// //     pthread_join(tid, &ret);
// //     if (ret == PTHREAD_CANCELED)
// //         printf("thread return, thread id %X, return code:PTHREAD_CANCELED\n", tid);
// //     else
// //         printf("thread return, thread id %X, return code:NULL\n", tid);
// // }

// // int main()
// // {
// //     pthread_t tid;
// //     void* ret;

// //     pthread_create(&tid,nullptr,thread1,nullptr);
// //     //这里的&ret是一个(void**)
// //     pthread_join(tid,&ret);
// //     printf("thread return,thread id:%x,return code:%d\n",\
// //     tid,*(int*)ret);
// //     free(ret);

// //     pthread_create(&tid,nullptr,thread2,nullptr);
// //     pthread_join(tid,&ret);
// //      printf("thread return,thread id:%x,return code:%d\n",\
// //     tid,*(int*)ret);
// //     free(ret);

// //     pthread_create(&tid,nullptr,thread3,nullptr);
// //     sleep(3);
// //     pthread_cancel(tid);
// //     pthread_join(tid,&ret);
// //      printf("thread return,thread id:%x,return code:%d\n",\
// //     tid,*(int*)ret);

// //     if(ret==PTHREAD_CANCELED)
// //         printf("thread return,thread is:%X,return code:PTHREAD_CANCELED\n");
// //     else
// //     {
// //         printf("thread return,thread id :%X,return code:nullptr\n",tid);
// //     }
// //     return 0;
// // }
// // int main()
// // {
// //     pthread_t tid;
// //     pthread_create(tid,nullptr,threadRoutine,(void*)"thread 1");

// //     printf("%lu,%p\n",tid,tid);
// //     int count=0;
// //     while(true)
// //     {
// //         cout<<"main thread:"<<"Running ..."
// //         <<pthread_self()<<endl;
// //         sleep(1);
// //         count++;
// //         if(count==5)
// //         break;
// //     }
// //     pthread_cancel(tid);
// //     cout<<"pthread cancel"<<endl;

// //     return 0;
// // }
// // 全局变量带来的结果就是每一个线程都会有一个相同的变量
// // int g_val=0;
// // 线程谁先运行与调度器有关，用户无法决定
// // 线程一旦异常，都可能会导致整个进程的退出
// // void* threadRoutine(void* args)
// // {
// //     //这里进行线程分离，避免因为一个线程的异常而导致整个
// //     //进程退出
// //     //pthread_detach(pthread_self());
// //     sleep(5);
// //     while(true)
// //     {
// //         cout<<(char*)args<<":"<<g_val<<"&"<<&g_val<<endl;
// //         g_val++;
// //         sleep(1);
// //         int a=10;
// //         a/=0;
// //         break;
// //     }
// //     pthread_exit((void*)11);
// // }
// // int main()
// // {
// //     pthread_t tid;
// //     pthread_create(&tid,nullptr,threadRoutine,(void*)"thread 1");

// //     while(true)
// //     {
// //         cout<<"main thread"<<":"<<g_val<<"&"<<&g_val<<endl;
// //         sleep(1);
// //         break;
// //     }
// //     //如果成功则返回0，如果失败则返回相应的错误码
// //     int n=pthread_join(tid,nullptr);
// //     cout<<"n:"<<n<<endl<<"errstring: "<<strerror(n)<<endl;
// //     return 0;
// // }
// // void func()
// // {
// //     while(true)
// //     {
// //         cout<<"hello new thread"<<endl;
// //         sleep(1);
// //     }
// // }

// // int main()
// // {
// //     thread t(func);
// //     thread t1(func);

// //     while(true)
// //     {
// //         cout<<"hello main thread"<<endl;
// //         sleep(1);
// //     }

// //     tm.join();
// // }

// // using namespace std;

// // int tickets=100;
// // void* getTickets(void* args)
// // {
// //     (void)args;
// //     while(true)
// //     {
// //         if(tickets > 0)
// //         {
// //             usleep(100);
// //             tickets--;
// //             printf("%p,%d\n",pthread_self(),tickets);
// //         }
// //         else
// //         {
// //             break;
// //         }
// //     }
// //     return nullptr;
// // }
// // int main()
// // {
// //     pthread_t t1,t2,t3,t4,t5;
// //     pthread_create(&t1,nullptr,getTickets,nullptr);
// //     pthread_create(&t2,nullptr,getTickets,nullptr);
// //     pthread_create(&t3,nullptr,getTickets,nullptr);
// //     pthread_create(&t4,nullptr,getTickets,nullptr);
// //     pthread_create(&t5,nullptr,getTickets,nullptr);

// //     pthread_join(t1,nullptr);
// //     pthread_join(t2,nullptr);
// //     pthread_join(t3,nullptr);
// //     pthread_join(t4,nullptr);
// //     pthread_join(t5,nullptr);

// //     return 0;
// // }
// // int tickets=100;
// // void* getTickets(void* args)
// // {
// //     (void)args;
// //     while(true)
// //     {
// //         if(tickets > 0)
// //         {
// //             usleep(100);
// //             printf("%p,%d\n",pthread_self(),tickets);
// //             tickets--;
// //         }
// //         else
// //         {
// //             break;
// //         }
// //     }
// //     return nullptr;
// // }

// // int main()
// // {
// //     //由于这里没有加锁保护所以也就导致了抢票的混乱
// //     pthread_t t1,t2,t3;
// //     //这里没有给回调函数传递参数
// //     pthread_create(&t1,nullptr,getTickets,nullptr);
// //     pthread_create(&t2,nullptr,getTickets,nullptr);
// //     pthread_create(&t3,nullptr,getTickets,nullptr);

// //     //这里的第二个参数是用户定义的二级指针，用来返回线程返回码的指针
// //     pthread_join(t1,nullptr);
// //     pthread_join(t2,nullptr);
// //     pthread_join(t3,nullptr);
// //     return 0;
// // }
// // int tickets=100;

// // void* getTickets(void* args)
// // {
// //     (void)args;
// //     while(true)
// //     {
// //         if(tickets > 0)
// //         {
// //             usleep(1000);
// //             printf("%p,%d\n",pthread_self(),tickets);
// //             tickets--;
// //         }
// //         else
// //         {
// //             break;
// //         }
// //     }
// //     return nullptr;
// // }

// // int g_val=0;
// // int* data=new int[10];
// // int i=0;
// // void* threadRoutine(void* args)
// // {
// //     pthread_detach(pthread_self());
// //     while(true)
// //     {
// //         cout<<(char*)args<<":"<<"&"<<&g_val<<endl;
// //         sleep(1);
// //         data[i]=i;
// //         if(i++==3)
// //             break;
// //     }
// //     pthread_exit((void*)11);
// //     cout<<"new thread quit"<<endl;
// //     //这里的返回时返回给主线程
// //     return (void*)data;
// // }
// // int main()
// // {
// //     pthread_t tid;
// //     pthread_create(&tid,nullptr,threadRoutine,(void*)"thread 1");

// //     while(true)
// //     {
// //         cout<<"main thread"<<":"<<g_val<<"&"<<&g_val<<endl;
// //         sleep(1000);
// //         break;
// //     }
// //     //这里设置线程等待
// //     int n=pthread_join(tid,nullptr);
// //     cout<<"n:"<<n<<"errstring"<<strerror(n)<<endl;

// //     printf("%lu,%p",tid,tid);
// //     int count=0;
// //     while(true)
// //     {
// //         cout<<"main 线程"
// //         <<"running ...main tid"<<pthread_self()<<endl;
// //         sleep(1);
// //         count++;
// //         if(count>=5)
// //         {
// //             break;
// //         }
// //     }
// //     pthread_cancel(tid);
// //     cout<<"pthread cancle:"<<tid<<endl;

// //     int* ret=nullptr;
// //     //这里默认会阻塞等待新线程退出
// //     pthread_join(tid,(void**)&ret);
// //     cout<<"main thread wait done ...main quit"
// //     <<(long long)ret<<endl;
// //     sleep(5);
// //     for(int i=0;i<10;i++)
// //     {
// //         cout<<ret[i]<<endl;
// //     }
// //     while(true)
// //     {
// //         cout<<"main thread"<<"running..."<<endl;
// //     }
// //     return 0;
// // }
